﻿using Chaunce.FrameWork.NetCore.Chaunce.Utility.Helpers;
using Chaunce.FrameWork.NetCore.SysCore;
using Chaunce.FrameWork.NetCore.SysCore.Configuration;
using Chaunce.FrameWork.NetCore.SysCore.Consts;
using Chaunce.FrameWork.NetCore.SysCore.Infrastructure;
using Chaunce.FrameWork.NetCore.SysCore.Infrastructure.Attributes;
using Chaunce.FrameWork.NetCore.Utility.Exceptions;
using Chaunce.Web.Core.Helpers;
using EnumsNET;
using Microsoft.AspNetCore.Http.Extensions;
using Microsoft.AspNetCore.Http.Internal;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
using Serilog;
using Serilog.Events;
using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Text;
using System.Threading.Tasks;

namespace Chaunce.Web.Core.Filters
{
    /// <summary>
    /// 全局异常捕获过滤器
    /// </summary>
    public class ChaunceExceptionFilter : IAsyncExceptionFilter
    {
        private static readonly ILogger logger = Log.ForContext<ChaunceExceptionFilter>();

        public async Task OnExceptionAsync(ExceptionContext context)
        {
            var config = EngineContext.Current.Resolve<ChaunceConfig>();
            string requestBodyText = string.Empty;
            var request = context.HttpContext.Request;
            var method = request.Method.ToUpper();
            var url = UriHelper.GetDisplayUrl(request);
            var macName = Environment.MachineName;
            var requestIp = EngineContext.Current.Resolve<IWebHelper>().GetCurrentIpAddress();
            var exception = context.Exception;

            #region 获取body参数
            if (!(exception is ViewModelStateValidException))
            {
                requestBodyText = ActionFilterHelper.GetRequestBodyText(request);
            }
            #endregion

            AppErrorCode errorCode = AppErrorCode.None;
            string requestId = string.Empty;
            var errorMsg = "程序访问异常,请稍后重试！";
            //请求bindModel验证失败时 请求body参数
            if (exception is ViewModelStateValidException)
            {
                requestBodyText = ((ViewModelStateValidException)exception).BindModelText;
            }

            if (exception is ChaunceException)
            {
                var ChaunceEx = (ChaunceException)context.Exception;
                var exErrorCode = ChaunceEx.ErrorCode;
                errorMsg = ChaunceEx.Message;
                //判断errorCode是否为系统定义的错误代码
                if (((AppErrorCode)exErrorCode).IsValid())
                {
                    errorCode = (AppErrorCode)ChaunceEx.ErrorCode;
                }
                else
                {
                    errorCode = AppErrorCode.None;
                }
                requestId = ChaunceEx.RequestId;
            }
            var appName = "Api接口";
            if (config != null)
            {
                appName = config.ApplicationName;
            }
            //错误代码对应的日志级别
            ErrorLevel errorLevel = ErrorLevel.Error;
            var currentLevel = errorCode.GetAttributes()?.Get<ErrorCodeLevelAttribute>()?.Level;
            if (currentLevel.HasValue)
            {
                errorLevel = currentLevel.Value;
            }
            LogEventLevel eventLevel = LogEventLevel.Error;
            switch (errorLevel)
            {
                case ErrorLevel.Error:
                    eventLevel = LogEventLevel.Error;
                    break;
                case ErrorLevel.Fatal:
                    eventLevel = LogEventLevel.Fatal;
                    break;
                case ErrorLevel.Warning:
                    eventLevel = LogEventLevel.Warning;
                    exception = null;
                    break;
            }
            //写入日志系统
            logger.Write(eventLevel, exception, "{0}异常.errorCode:{1},errorMsg:{2},请求url:{3},请求Body:{4},请求IP:{5},服务器名称:{6}", appName, errorCode, errorMsg, url, requestBodyText, requestIp, macName);

            //自定义异常返回
            context.Result = errorMsg.ToErrorActionResult(errorCode.ToInt());
            context.HttpContext.Response.StatusCode = (int)HttpStatusCode.OK;
            context.ExceptionHandled = true;
            return;
        }
    }
}
